package structure

import (
	"bytes"
	"errors"
	"io"
	"unicode/utf8"
)

const (
	// 初始化分配缓存容量下限
	smallBufferCap = 64

	// Buffer.ReadFrom()在从io.Reader中读取数据过程中,每次缓冲区扩容上限
	// 一定程度上等同于每次从io.Reader中读取的数据上限
	MinRead = 512
)

var (
	// 当内存不能被分配到一个缓冲区中用来缓存数据时,会触发这个panic错误
	ErrorTooLarge = errors.New("structure.Buffer: too large")

	// 当io.Reader返回的读取字节数为负数时,会触发这个panic错误
	ErrorNegativeRead = errors.New("structure.Buffer: reader returned negative count from Read")

	// 当io.Writer返回的写入字节数大于缓存区有效自己输时,会触发这个panic错误
	ErrorInvalidWriteCount = errors.New("structure.Buffer: invalid write count")

	// 当Truncate接收的参数n超过未读取区域长度时,会触发这个panic错误
	ErrorTruncateOutOfRange = errors.New("structure.Buffer: truncation out of range")

	// 当Grow接收的参数n为负数时,会触发这个panic错误
	ErrorGrowNegativeCount = errors.New("structure.Buffer: grow negative count")

	// 当AdjustCap接收的参数n为负数时,会触发这个panic错误
	ErrorCapNegativeCount = errors.New("structure.Buffer: cap negative count")

	// 当UnreadRune操作失败时,会返回这个错误
	ErrorUnreadRuneFailed = errors.New("structure.Buffer: UnreadRune rollback ReadRune operation failed")

	// 当UnreadByte操作失败时,会返回这个错误
	ErrorUnreadByteFailed = errors.New("structure.Buffer: UnreadByte rollback ReadByte operation failed")

	// 当WriteNextEnd接收的参数n会导致越界时,会触发这个panic错误
	ErrorWriteNextEndOutOfRange = errors.New("structure.Buffer: WriteNextEnd out of range")
)

// 缓冲区类型
// 通过对记录的操作类型的校验,判断UnreadRune()和UnreadByte()是否可用
// 将其转换为int类型后,就是操作影响的缓冲区大小
type readOp int8

// 为了确保操作对应的值是确定的,这里不能使用iota
const (
	opRead      readOp = -1 // 其它任意读取操作
	opInvalid   readOp = 0  // 没有读取操作
	opReadRune1 readOp = 1  // 读取rune数 1
	opReadRune2 readOp = 2  // 读取rune数 2
	opReadRune3 readOp = 3  // 读取rune数 3
	opReadRune4 readOp = 4  // 读取rune数 4
)

// 缓存结构
// 类似标准包bytes.Buffer
// 增加对数据尾部之后一段内存空间直接操作的接口
// 根据策略,通过将有效数据拷贝移动到缓存区头位置的方式,提高既有内存的利用率
type Buffer struct {
	// 缓存数据
	// 有效数据为 buf[off : len(buf)]
	buf []byte

	// 有效数据起始位置索引
	// 读数据从&buf[off]开始
	// 写数据从&buf[len(buf)]开始
	off int

	// 记录上次读取操作
	// 用于判断Unread*()是否可用
	lastRead readOp
}

// 获取未读取数据长度
func (b *Buffer) Len() int {
	return len(b.buf) - b.off
}

// 获取缓存区容量
func (b *Buffer) Cap() int {
	return cap(b.buf)
}

// 获取可用缓存区域长度
func (b *Buffer) Available() int {
	return b.Cap() - b.Len()
}

// 返回未读取的有效数据
// 返回的切片与Buffer.buf共享内存
// 所以,在Buffer.buf指向的内存更改之前,所有该方法返回的切片以及缓存区会被相互影响
func (b *Buffer) Bytes() []byte {
	return b.buf[b.off:]
}

// 返回可用的缓存区域
// 返回的切片与Buffer.buf共享内存
// 所以,在Buffer.buf指向的内存更改之前,所有该方法返回的切片以及缓存区会被相互影响
func (b *Buffer) AvailableBuffer() []byte {
	b.tidy()
	return b.buf[len(b.buf):]
}

// 将未读取数据作为字符串返回
// 如果Buffer指针为空时,返回"<nil>"
func (b *Buffer) String() string {
	if b == nil {
		return "<nil>"
	}
	return string(b.buf[b.off:])
}

// 截断未读取数据
// 使用的缓存区域还是同一个
// 如果参数n为负数或大于未读取数据长度会触发panic
func (b *Buffer) Truncate(n int) {
	if n == 0 {
		b.Reset()
		return
	}

	b.lastRead = opInvalid
	if n < 0 || n > b.Len() {
		panic(ErrorTruncateOutOfRange)
	}
	b.buf = b.buf[:b.off+n]
	b.tidy()
}

// 调整缓存容量
// 将容量调整为大于等于n的 smallBufferCap 最小整数倍容量
// 如果n是负数会触发panic
// 如果缓存区不能扩容时,会用ErrorTooLarge触发panic
func (b *Buffer) AdjustCap(n int) {
	if n < 0 {
		panic(ErrorCapNegativeCount)
	}
	b.adjustCap(n)
}

// 重置清空缓存区域
// 使用的缓存区域还是同一个
// 该操作与Truncate(0)效果等同
func (b *Buffer) Reset() {
	b.buf = b.buf[:0]
	b.off = 0
	b.lastRead = opInvalid
}

// 扩容缓存区
// 在现有缓存区的基础上扩容,大于等于n的 smallBufferCap 最小整数倍容量
// 调用该方法后,至少n字节可以在不额外分配内存的情况下写入缓存区
// 如果n是负数会触发panic
// 如果缓存区不能扩容时,会用ErrorTooLarge触发panic
func (b *Buffer) Grow(n int) {
	if n < 0 {
		panic(ErrorGrowNegativeCount)
	}
	b.grow(n)
}

// 将p的数据写入缓存区,必要时会自动扩容缓存区
// 返回值n是p的长度,err必定是nil
// 如果缓存区不能扩容时,会用ErrorTooLarge触发panic
func (b *Buffer) Write(p []byte) (n int, err error) {
	b.lastRead = opInvalid
	m := b.writeCheck(len(p))
	return copy(b.buf[m:], p), nil
}

// 将s的数据写入缓存区,必要时会自动扩容缓存区
// 返回值n是s的长度,err必定是nil
// 如果缓存区不能扩容时,会用ErrorTooLarge触发panic
func (b *Buffer) WriteString(s string) (n int, err error) {
	b.lastRead = opInvalid
	m := b.writeCheck(len(s))
	return copy(b.buf[m:], s), nil
}

// 将r中的数据读取到缓存区,必要时会自动扩容缓存区
// 返回值n是读取到的总字节数
// 读取数据期间发生的初io.EOF外的所有错误都将中断读取,并返回该错误
// 如果缓存区不能扩容时,会用ErrorTooLarge触发panic
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
	b.lastRead = opInvalid
	for {
		i := b.writeCheck(MinRead)
		m, e := r.Read(b.buf[i:cap(b.buf)])
		if m < 0 {
			panic(ErrorNegativeRead)
		}

		b.buf = b.buf[:i+m]
		n += int64(m)
		// EOF应该视作没有错误
		if e == io.EOF {
			return n, nil
		}
		if e != nil {
			return n, e
		}
	}
}

// 将缓存区的数据写入到w,直到数据写完或发生错误
// 返回值n是写入字节数,为了现实io.WriteTo,将int强转为了int64
// 写入数据期间发生的任何错误都将会返回
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
	b.lastRead = opInvalid
	if nBytes := b.Len(); nBytes > 0 {
		m, e := w.Write(b.buf[b.off:])
		if m > nBytes {
			panic(ErrorInvalidWriteCount)
		}
		b.off += m
		n = int64(m)
		if e != nil {
			return n, e
		}
		if m != nBytes {
			return n, io.ErrShortWrite
		}
	}
	b.Reset()
	return n, nil
}

// 将c写入缓存区,必要时会自动扩容缓存区
// 返回值error必定是nil,这是为了实现bufio.Writer的WriteByte接口
// 如果缓存区不能扩容时,会用ErrorTooLarge触发panic
func (b *Buffer) WriteByte(c byte) error {
	b.lastRead = opInvalid
	m := b.writeCheck(1)
	b.buf[m] = c
	return nil
}

// 将r写入缓存区,必要时会自动扩容缓存区
// 返回值n是r写入到缓存区的字节数
// 返回值error必定是nil,这是为了实现bufio.Writer的WriteRune接口
// 如果缓存区不能扩容时,会用ErrorTooLarge触发panic
func (b *Buffer) WriteRune(r rune) (n int, err error) {
	if uint32(r) < utf8.RuneSelf {
		b.WriteByte(byte(r))
		return 1, nil
	}

	b.lastRead = opInvalid
	m := b.writeCheck(utf8.UTFMax)
	n = utf8.EncodeRune(b.buf[m:m+utf8.UTFMax], r)
	b.buf = b.buf[:m+n]
	return n, nil
}

// 以从前往后的顺序从有效数据中读取数据到p中,直到数据读取完或p写满
// 返回值n是读取到的字节数
// 返回值err,如果缓存区没有数据可以读取,将是io.EOF错误(除非p的长度是0), 其他情况都是nil
func (b *Buffer) Read(p []byte) (n int, err error) {
	b.lastRead = opInvalid
	if b.empty() {
		b.Reset()
		if len(p) == 0 {
			return 0, nil
		}
		return 0, io.EOF
	}

	n = copy(p, b.buf[b.off:])
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	return n, nil
}

// 返回的切片是以从前往后的顺序从有效数据中读取到的n字节数据
// 如果有效数据长度小于n,会将整个有效数据作为切片返回
// 返回的切片与Buffer.buf共享内存
// 所以,在Buffer.buf指向的内存更改之前,所有该方法返回的切片以及缓存区会被相互影响
func (b *Buffer) Next(n int) []byte {
	b.lastRead = opInvalid
	m := b.Len()
	if n > m {
		n = m
	}
	data := b.buf[b.off : b.off+n]
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	return data
}

// 读取有效数据从前往后的第一个字节
// 如果有效数据为空,将返回io.EOF错误
func (b *Buffer) ReadByte() (byte, error) {
	if b.empty() {
		b.Reset()
		return 0, io.EOF
	}

	c := b.buf[b.off]
	b.off++
	b.lastRead = opRead
	return c, nil
}

// 读取有效数据从前往后的第一个utf8编码字符
// 如果有效数据为空,将返回io.EOF错误
// 如果这个字符是错误的utf8编码,将消耗一个字节,并返回 U+FFFD,1
func (b *Buffer) ReadRune() (r rune, size int, err error) {
	if b.empty() {
		b.Reset()
		return 0, 0, io.EOF
	}
	c := b.buf[b.off]
	if c < utf8.RuneSelf {
		b.off++
		b.lastRead = opReadRune1
		return rune(c), 1, nil
	}
	r, n := utf8.DecodeRune(b.buf[b.off:])
	b.off += n
	b.lastRead = readOp(n)
	return r, n, nil
}

// 回滚上一次ReadRune操作
// 如果上一次读写操作不是一个成功的ReadRune,将返回错误
func (b *Buffer) UnreadRune() error {
	if b.lastRead <= opInvalid {
		return ErrorUnreadRuneFailed
	}
	if b.off >= int(b.lastRead) {
		b.off -= int(b.lastRead)
	}
	b.lastRead = opInvalid
	return nil
}

// 回滚上一次读数据操作,仅恢复最后一个字节
// 如果上一次读操作后发生了写操作,或者读操作失败,或者读到0字节,将返回错误
func (b *Buffer) UnreadByte() error {
	if b.lastRead == opInvalid {
		return ErrorUnreadByteFailed
	}
	b.lastRead = opInvalid
	if b.off > 0 {
		b.off--
	}
	return nil
}

// 从缓存数据中找到第一个分隔符,并读取起始位置到该字节的数据拷贝返回
// 如果在找到分隔符之前遇到错误,将返回反正错误之前读取到的数据以及错误本身(通常为io.EOF)
// 当且仅当返回的数据不以分隔符结尾时,返回的err才不为nil
func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) {
	slice, err := b.readSlice(delim)
	line = append(line, slice...)
	return line, err
}

// 与ReadBytes相同,只是以字符串形式返回数据
func (b *Buffer) ReadString(delim byte) (line string, err error) {
	slice, err := b.readSlice(delim)
	return string(slice), err
}

// 返回紧接着有效数据区域后n字节的缓存区域
// 返回的切片与Buffer.buf共享内存
// 该方法应当搭配WriteNextEnd()一起使用
func (b *Buffer) WriteNextBegin(n int) []byte {
	m := b.writeCheck(n)
	next := b.buf[m:]
	b.buf = b.buf[:m]
	return next
}

// 将有效数据区域向后扩展n字节
// 该方法应当搭配WriteNextBegin()一起使用,在返回的切片中写入了多少数据,调用这个方法时就扩展多少字节
// 如果向后扩展n字节会越界时,会用ErrorWriteNextEndOutOfRange触发panic
func (b *Buffer) WriteNextEnd(n int) {
	if n < 0 {
		return
	}
	m := len(b.buf)
	if m+n > cap(b.buf) {
		panic(ErrorWriteNextEndOutOfRange)
	}

	b.lastRead = opInvalid
	b.buf = b.buf[:m+n]
}

// 判断未读取数据是否为空
func (b *Buffer) empty() bool {
	return len(b.buf) <= b.off
}

// 包含上次读取数据的有效数据其实位置
func (b *Buffer) lastOff() (int, int) {
	hide := 0
	if b.lastRead > opInvalid {
		hide = int(b.lastRead)
	}
	return b.off - hide, hide
}

// 整理缓存区 拷贝移动未读取数据到缓存区头位置
func (b *Buffer) tidy() {
	// 为了保证Unread*()能够正常执行,需要将上次读取的数据一起保留
	off, hide := b.lastOff()

	// 当有效数据起始位置是缓存区起始位置时,不需要任何操作
	if off == 0 {
		return
	}

	len := len(b.buf) - off
	copy(b.buf[:], b.buf[off:])
	b.buf = b.buf[:len]
	b.off = hide
}

// 扩容缓存区,大于n的 smallBufferCap 最小整数倍容量
// 如果缓存区域不能再扩容时会用ErrorTooLarge触发panic
func (b *Buffer) grow(n int) {
	defer func() {
		if recover() != nil {
			panic(ErrorTooLarge)
		}
	}()

	// 为了保证Unread*()能够正常执行,需要将上次读取的数据一起保留
	off, hide := b.lastOff()

	// 目标容量应当能容纳现有未读取长度+上次读取长度+n,且是最小缓存容量的整数倍
	total := b.Len() + hide + n
	multi := total / smallBufferCap
	if total%smallBufferCap != 0 {
		multi++
	}

	buf := make([]byte, multi*smallBufferCap)
	l := len(b.buf)
	copy(buf, b.buf[off:l])
	b.buf = buf[:l-off]
	b.off = hide
}

// 调整缓存区,大于n的 smallBufferCap 最小整数倍容量
// 如果缓存区域不能再扩容时会用ErrorTooLarge触发panic
func (b *Buffer) adjustCap(total int) {
	defer func() {
		if recover() != nil {
			panic(ErrorTooLarge)
		}
	}()

	// 为了保证Unread*()能够正常执行,需要将上次读取的数据一起保留
	off, hide := b.lastOff()

	// 目标容量应当能容纳现有未读取长度+上次读取长度,且是最小缓存容量的整数倍
	if total < b.Len()+hide {
		total = b.Len() + hide
	}
	multi := total / smallBufferCap
	if total%smallBufferCap != 0 {
		multi++
	}

	// 容量相同时不用调整
	newCap := multi * smallBufferCap
	if newCap == cap(b.buf) {
		return
	}

	buf := make([]byte, newCap)
	l := len(b.buf)
	copy(buf, b.buf[off:l])
	b.buf = buf[:l-off]
	b.off = hide
}

// 检查是否能写入n字节到缓存区,不能则扩容
// 返回可写入数据位置
func (b *Buffer) writeCheck(n int) int {
	// 不能够在未读取数据之后直接写入需要整理缓存区或扩容
	if cap(b.buf)-len(b.buf) < n {
		if _, hide := b.lastOff(); b.Available()-hide >= n {
			// 真实的可用缓存区满足条件,需要整理后才能写入
			b.tidy()
		} else {
			// 缓冲区扩容
			b.grow(n)
		}
	}

	m := len(b.buf)
	b.buf = b.buf[:m+n]
	return m
}

// 从缓存数据中找到第一个指定字节,并读取起始位置到该字节的数据作为切片返回
func (b *Buffer) readSlice(delim byte) (line []byte, err error) {
	i := bytes.IndexByte(b.buf[b.off:], delim)
	end := b.off + i + 1
	if i < 0 {
		end = len(b.buf)
		err = io.EOF
	}

	line = b.buf[b.off:end]
	b.off = end
	b.lastRead = opRead
	return line, err
}

// NewBuffer使用buf作为其初始内容创建并初始化一个新的Buffer
// 新的Buffer获取buf的所有权, 调用者在调用之后不应该再使用buf
// 它还可以用于设置用于写入的内部缓冲区的初始大小,要做到这一点, 但应该具有所需的容量但长度为零.
// 在大多数情况下, new(Buffer)(或者仅仅声明一个Buffer变量)就足以初始化Buffer
func NewBuffer(buf []byte) *Buffer {
	return &Buffer{buf: buf}
}

// NewBuffer使用s作为其初始内容创建并初始化一个新的Buffer
// 在大多数情况下, new(Buffer)(或者仅仅声明一个Buffer变量)就足以初始化Buffer
func NewBufferString(s string) *Buffer {
	return &Buffer{buf: []byte(s)}
}
